﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using wwl.Domain.Entities.Rbac;

namespace wwl.DataAccess.Mappings.Rbac
{
  /// <summary>
  /// 用户角色关联实体映射配置类（EF Core 数据映射）
  /// 负责配置用户角色关联实体与数据库表 rbac_user_role 之间的映射关系和关联约束
  /// 核心价值：实现用户与角色多对多关系的持久化，构建RBAC权限模型的用户-角色关联链路
  /// 设计目标：确保关联数据的完整性和一致性，支撑高效的用户权限查询和角色成员管理
  /// </summary>
  public class UserRoleMap : IEntityTypeConfiguration<UserRole>
  {
    /// <summary>
    /// 配置用户角色关联实体的数据库映射细节
    /// </summary>
    /// <param name="builder">实体类型构建器，提供流畅API配置关联实体的映射规则</param>
    /// <remarks>
    /// 1. 关联完整性：通过外键约束确保用户和角色引用的有效性，维护关联数据的业务一致性
    /// 2. 唯一性保障：联合唯一约束防止重复的用户角色分配，避免权限配置的混乱和冲突
    /// 3. 性能优化：针对用户查询角色和角色查询用户的双向场景设计合适的索引策略
    /// 4. 级联策略：合理的级联删除设置确保关联数据清理的完整性和数据清洁度
    /// </remarks>
    public void Configure(EntityTypeBuilder<UserRole> builder)
    {
      // 指定表名：明确映射到 rbac_user_role 表，保持RBAC模块关联表命名的一致性
      builder.ToTable("rbac_user_role");

      // 配置主键：使用字符串类型主键，支持UUID等多种ID生成策略
      builder.HasKey(x => x.Id);

      #region 属性映射配置
      // 主键映射：64字符长度与用户和角色主键保持一致，NOT NULL 约束确保关联记录标识完整性
      builder.Property(x => x.Id)
          .HasColumnName("id")
          .HasMaxLength(64)
          .IsRequired();

      // 用户标识映射：关联 rbac_user.id，外键约束确保关联用户的存在性和有效性
      builder.Property(x => x.UserId)
          .HasColumnName("user_id")
          .HasMaxLength(64)
          .IsRequired();

      // 角色标识映射：关联 rbac_role.id，外键约束确保关联角色的存在性和有效性
      builder.Property(x => x.RoleId)
          .HasColumnName("role_id")
          .HasMaxLength(64)
          .IsRequired();

      // 租户标识映射：64字符长度与用户和角色租户标识保持一致，保障关联关系的租户一致性
      builder.Property(x => x.TenantId)
          .HasColumnName("tenant_id")
          .HasMaxLength(64);

      // 操作类型映射：记录对用户角色关联的操作类型（分配、撤销、更新）
      // 映射到数据库的 operation_type 字段，VARCHAR(20) 类型，并设置默认值为 'ASSIGN'
      builder.Property(x => x.OperationType)
          .HasColumnName("operation_type")
          .HasMaxLength(20)
          .HasDefaultValue("ASSIGN")
          .IsRequired();

      // 基础实体属性映射：继承自 BaseEntity 的审计字段和软删除支持
      builder.Property(x => x.CreatedTime)
          .HasColumnName("created_time")
          .IsRequired();

      builder.Property(x => x.UpdatedTime)
          .HasColumnName("updated_time")
          .IsRequired();

      builder.Property(x => x.CreatedBy)
          .HasColumnName("created_by")
          .HasMaxLength(64)
          .IsRequired();

      builder.Property(x => x.Remarks)
          .HasColumnName("remarks")
          .HasColumnType("text");

      builder.Property(x => x.IsDeleted)
          .HasColumnName("is_deleted")
          .HasDefaultValue(false);
      #endregion

      #region 外键关系配置
      // 用户外键关系：建立与用户实体的多对一关系，级联删除确保用户删除时关联记录同步清理
      builder.HasOne(ur => ur.User)
          .WithMany(u => u.UserRoles)
          .HasForeignKey(ur => ur.UserId)
          .OnDelete(DeleteBehavior.Cascade);

      // 角色外键关系：建立与角色实体的多对一关系，级联删除确保角色删除时关联记录同步清理
      builder.HasOne(ur => ur.Role)
          .WithMany(r => r.UserRoles)
          .HasForeignKey(ur => ur.RoleId)
          .OnDelete(DeleteBehavior.Cascade);
      #endregion

      #region 索引配置
      // 租户索引：支持按租户查询用户角色关联关系，优化多租户数据隔离场景的查询性能
      builder.HasIndex(x => x.TenantId)
          .HasDatabaseName("ix_rbac_user_role_tenant_id");

      // 联合唯一约束：确保同一用户不能重复分配同一角色，防止权限配置的重复和冲突
      builder.HasIndex(x => new { x.UserId, x.RoleId })
          .IsUnique()
          .HasDatabaseName("uk_rbac_user_role_user_role");

      // 操作类型索引：如果业务中存在大量根据操作类型进行的查询或统计，可以考虑添加此索引
      // 例如：查询所有被撤销(REVOKE)的用户角色关联记录
      builder.HasIndex(x => x.OperationType)
          .HasDatabaseName("ix_rbac_user_role_operation_type");
      #endregion
    }
  }
}